package framework.utils.http;

import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

import org.xml.sax.SAXException;

import framework.Service;
import framework.server.ServerException;
import framework.utils.Conn;
import framework.utils.http.Http;
import framework.utils.http.HttpRequest;
import framework.utils.http.HttpResponse;

/**
 *
 * @author	Orlin Tomov
 * @version	0.2
 */
public class HttpConn extends Conn {

	private static final String APPSERVER = "AppServer Framework";

	protected Service service = null;
	protected String link = null;

	public HttpConn(Service service, String link) throws IOException {
		this(service, link, Http.HTTP_PORT);
	}

	public HttpConn(Service service, String link, int port) throws IOException {
		super(getHost(link), port);
		setLink(link);
		this.service = service;
		// System.out.println("link: "+link);
	}

	/**
	 * @param	socket
	 * @throws	IOException
	 */
	public HttpConn(Service service, Socket socket) throws IOException {
		super(socket);
		this.service = service;
	}

	private void setLink(String text) {
		link = text.replaceAll(" ", "%20");
		if (link.startsWith(Http.HTTPS)) {
			port = Http.SSL_PORT;
		}
		if (link.startsWith(Http.HTTP) || link.startsWith(Http.HTTPS)) {
			int portPos = link.substring(Http.HTTPS.length()).indexOf(":");
			if (portPos > 0) {
				portPos += Http.HTTPS.length();
				int locationPos = link.substring(Http.HTTPS.length()).indexOf("/") + Http.HTTPS.length();
				if (portPos < locationPos) {
					String p = link.substring(portPos + 1, locationPos);
					port = Integer.parseInt(p);
					link = link.substring(0, portPos) + link.substring(locationPos);
				}
			}
		}
	}

	/**
	 * Requests via http
	 */
	protected void request(boolean post, List<Object> request, String HTTP) {
		String link = this.link;
		String host = null;
		if (link.startsWith(Http.HTTP) || link.startsWith(Http.HTTPS)) {
			if (link.startsWith(Http.HTTP)) {
				link = link.substring(Http.HTTP.length());
			} else {
				link = link.substring(Http.HTTPS.length());
				HTTP = Http.HTTP_1_1;
			}
			if (link.indexOf("/") >= 0) {
				host = link.substring(0, link.indexOf("/"));
				link = link.substring(link.indexOf("/"));
			}
		}
		HttpRequest http = new HttpRequest(link, post, HTTP);
		http.add(Http.USER_AGENT + APPSERVER);
		if (host != null) {
			http.add(Http.HOST + host);
		}
		if (request != null) {
			http.addAll(request);
		}
		http.print(out);
	}

	/**
	 * Get responce via http
	 * 
	 * @return	lines of response
	 * @throws	IOException
	 * @throws	SAXException
	 * @throws	ServerException
	 */
	protected List<Object> response(boolean post, String id, int count, List<String> from) throws SAXException, IOException, ServerException
	{
		HttpResponse response = new HttpResponse(1000);
		List<Object> lines = null;
		SAXException sax = null;
		try {
			lines = response.parse(in);
		} catch (SAXException e) {
			sax = e;
			lines = response.getLines();
		} finally {
			close();
		}
		for (int i = 0; i < lines.size(); i++) {
			if (lines.get(i) instanceof String) {
				if (((String) lines.get(i)).startsWith("Location: ")) {
					String location = ((String)lines.get(i)).substring("Location: ".length());
					if (!location.startsWith(Http.HTTP) && !location.startsWith(Http.HTTPS)) {
						if (link.startsWith(Http.HTTPS)) {
							location = Http.HTTPS + getHost(link) + location;
						} else {
							location = Http.HTTP + getHost(link) + location;
						}
					}
					if (!link.equalsIgnoreCase(location)) {
						HttpConn conn = new HttpConn(service, location);
						try {
							conn.request(post, null, null);
							while (lines.size() - 1 > i) {
								lines.remove(lines.size() - 1);
							}
							while (lines.size() > 2) {
								lines.remove(lines.size() - 2);
							}
							if (from == null) {
								from = new ArrayList<String>();
							}
							for (int j = 0; j < from.size(); j++) {
								String line = from.get(j);
								if (line.equalsIgnoreCase(location)) {
									StringBuffer links = new StringBuffer("cicle links:\n");
									for (int k = 0; k < from.size(); k++) {
										links.append(from.get(k) + "\n");
									}
									links.append(location + "\n");
									// Server.log.debug(id + " - " + links.toString());
									throw new ServerException(links.toString());
								}
							}
							from.add(location);
							List<Object> realloc = conn.response(post, id, ++count, from);
							lines.addAll(realloc);
							return lines;
						} finally {
							conn.close();
						}
					}
				}
			}
		}
		if (sax != null) {
			throw sax;
		}
		return lines;
	}

	public static String getHost(String link) {
		if (link.startsWith(Http.HTTP) || link.startsWith(Http.HTTPS)) {
			String host;
			if (link.startsWith(Http.HTTP)) {
				host = link.substring(Http.HTTP.length());
			} else {
				host = link.substring(Http.HTTPS.length());
			}
			if (host.indexOf("/") > 0) {
				host = host.substring(0, host.indexOf("/"));
			}
			return host;
		} else {
			return link;
		}
	}

	/**
	 * @return the link.
	 */
	public String getLink() {
		return link;
	}
}
